﻿using RQX.Common.Core.File;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RQX.Common.Core.Logger
{
    public class LogUtils
    {
        private static ConcurrentDictionary<string, DateTime> delDic = new ConcurrentDictionary<string, DateTime>();
        private static ConcurrentDictionary<string, ConcurrentQueue<string>> logDic = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
        static LogUtils()
        {
            Task.Run(() =>
            {
                //Thread.CurrentThread.IsBackground = false;
                while (true)
                {
                    Thread.Sleep(1000);
                    foreach (var item in delDic)
                    {
                        if (item.Value.AddMilliseconds(10) < DateTime.Now)
                        {
                            logDic.TryRemove(item.Key, out var queue);
                            delDic.TryRemove(item.Key, out var time);
                        }
                    }
                }
            });
        }
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="msg"></param>
        public static void WriteLogToConsole(string msg)
        {
            Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss}\t{msg}");
        }
        public static void WriteDebugLog(string msg, string ip = "127.0.0.1", string dirName = "调试日志")
        {
            WriteErrorLog(msg, ip, dirName);
        }
        public static void WriteErrorLog(string msg, string ip = "127.0.0.1", string dirName = "错误日志")
        {
            var path = BuildPath(dirName, ip);
            WriteLog(path, msg);
        }
        public static void WriteLog(string filePath, string msg)
        {
            WriteLog(filePath, DateTime.Now, msg);
        }
        private static async void WriteLog(string filePath, DateTime? time, string msg)
        {
            FileUtils.CheckOrCreatePath(filePath);
            var queue = logDic.GetOrAdd(filePath, new ConcurrentQueue<string>());
            queue.Enqueue(BuildMsg(time, msg));
            delDic.AddOrUpdate(filePath, DateTime.Now, (s, t) => DateTime.Now);
            await Task.Run(() =>
            {
                Thread.CurrentThread.IsBackground = false;
                try
                {
                    using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Read))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                        {
                            var q = logDic.GetOrAdd(filePath, new ConcurrentQueue<string>());
                            while (q.TryDequeue(out string line))
                            {
                                Console.WriteLine(line);
                                sw.WriteLine(line);
                            }
                        }
                    }
                }
                catch { }
            });
        }
        public static string BuildPath(string dirName, string ip)
        {
            var time = DateTime.Now;
            var year = $"{time.Year:0000}";
            var month = $"{time.Month:00}";
            var day = $"{time.Day:00}";
            var fileName = $"{time:yyyyMMddHH}.log";
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dirName, ip, year, month, day, fileName);
            return path;
        }
        private static string BuildMsg(DateTime? time, string msg)
        {
            time = time ?? DateTime.Now;
            return $"{time.Value:yyyy-MM-dd HH:mm:ss} => {msg}";
        }
    }
}
